%% ========================================================================
% 计算图可视化分析最终汇总脚本 (Four-in-One Visualization Script)
%
% 本脚本包含四种不同的可视化方案，旨在从不同维度理解计算图。
% 运行后会生成四张独立的图，每张图都有其独特的分析视角。
% ========================================================================

clear; clc; close all;

%% ========================================================================
% 第一部分：数据加载与图对象创建 (所有可视化的共同基础)
% ========================================================================
disp('--- Section 1: Loading data and creating graph object ---');
try
    nodes_table = readtable('Conv_Case0_Nodes.csv');
    edges_table = readtable('Conv_Case0_Edges.csv');
    disp('数据文件加载成功。');
catch ME
    disp('错误：无法加载CSV文件。');
    disp('请确保 Conv_Case0_Nodes.csv 和 Conv_Case0_Edges.csv 文件在当前MATLAB工作目录下。');
    rethrow(ME);
end

% 使用明确的构造函数 digraph(s, t, [], NodePropertiesTable) 以确保稳健性
start_nodes = edges_table.StartNodeId + 1;
end_nodes = edges_table.EndNodeId + 1;
G = digraph(start_nodes, end_nodes, [], nodes_table);
disp(['成功创建带属性的图对象，包含 ' num2str(numnodes(G)) ' 个节点和 ' num2str(numedges(G)) ' 条边。']);
disp(' ');


%% ========================================================================
% 第二部分：图一 - 邻接矩阵稀疏图 (用于观察整体连接模式)
% ========================================================================
disp('--- Section 2: Generating Plot 1: Adjacency Matrix ---');
% --- 图的意义 ---
% 本图展示了计算图的"连接骨架"，用于回答"从宏观上看，哪些节点依赖于哪些节点？"这个问题。
% 它将图的所有依赖关系（边）压缩到了一个二维矩阵中。
%
% --- 如何理解 ---
% 1. 图中的每一个蓝点，都代表原始计算图中的一条依赖边。
% 2. 一个点的位置在 (Y, X)，意味着节点Y必须在节点X之前执行。
% 3. 请重点观察点的分布"模式"。如果点呈现出规律的、非随机的带状或块状结构，
%    这强烈暗示了计算任务本身是高度结构化的（例如，分层或分块的），而非混乱的。
figure('Name', '图一：邻接矩阵稀疏图 (整体连接模式)');
adj_matrix = adjacency(G);
spy(adj_matrix);
title('邻接矩阵稀疏图 (整体连接模式)');
xlabel('目标节点 ID (EndNodeId)');
ylabel('源节点 ID (StartNodeId)');
grid on;
disp('图一生成完毕。');
disp(' ');


%% ========================================================================
% 第三部分：图二 - 完整节点连接图 (用于感受整体规模)
% ========================================================================
disp('--- Section 3: Generating Plot 2: Full Node-Link Diagram ---');
% --- 图的意义 ---
% 本图尝试将全部2580个节点和3869条边都绘制出来。其主要意义在于提供一种
% 对计算任务"规模"和"密度"的直观感受。
%
% --- 如何理解 ---
% 1. 最重要的信息是这张图的"不可读性"。您会看到一个极其拥挤的"毛线球"。
% 2. 这种视觉上的混乱恰恰说明了，对于大规模计算图，我们不能用这种"一览无余"
%    的方式去分析细节，必须采用更高级、更抽象的可视化方法（如图一、三、四）。
figure('Name', '图二：完整节点连接图 (整体规模)');
p = plot(G, 'Layout', 'force');
p.EdgeAlpha = 0.1; % 降低边的透明度以缓解视觉混乱
title('完整节点连接图 (警告：可读性极差)');
disp('图二生成完毕。');
disp(' ');


%% ========================================================================
% 第四部分：图三 - 2跳邻域功能着色图 (用于分析局部详细逻辑)
% ========================================================================
disp('--- Section 4: Generating Plot 3: 2-Hop Functional Subgraph ---');
% --- 图的意义 ---
% 本图是一个"显微镜"，深入到计算图的某个局部，详细展示其内部的工作流。
% 它用于回答"在某个具体操作（如ID 10）的周围，资源是如何申请与释放的，数据又是如何流动的？"
%
% --- 如何理解 ---
% 1. 这是一个以ID 10为中心，向外扩展两层依赖关系所形成的局部网络。
% 2. 请重点观察"颜色"的含义：
%    - 绿色代表"资源申请"(ALLOC)，是一切的开始。
%    - 红色代表"资源释放"(FREE)，是生命周期的结束。
%    - 蓝色代表"数据搬运"，是流动的通道。
%    - 橙色代表"核心计算"，是真正产生价值的地方。
% 3. 通过追踪从绿色到红色的路径，可以清晰地看到一个缓冲区的完整生命周期。
figure('Name', '图三：2跳邻域功能着色图 (局部详细逻辑)');
center_node_id_1based = 11; % 以ID 10为例 (10+1=11)
hop1_neighbors = unique([predecessors(G, center_node_id_1based); successors(G, center_node_id_1based)]);
hop2_neighbors = [];
for i = 1:length(hop1_neighbors)
    hop2_neighbors = [hop2_neighbors; predecessors(G, hop1_neighbors(i)); successors(G, hop1_neighbors(i))];
end
subgraph_node_ids = unique([center_node_id_1based; hop1_neighbors; hop2_neighbors]);
subG = subgraph(G, subgraph_node_ids);
h = plot(subG, 'Layout', 'layered');
title(['以节点ID 10 为中心的2跳邻域功能图']);
% --- 功能着色 ---
alloc_color=[0.1 0.7 0.1]; free_color=[0.9 0.1 0.1]; compute_color=[1 0.6 0]; move_color=[0.2 0.5 1];
for i = 1:numnodes(subG)
    op = subG.Nodes.Op{i};
    if strcmp(op, 'ALLOC'), highlight(h, i, 'NodeColor', alloc_color);
    elseif strcmp(op, 'FREE'), highlight(h, i, 'NodeColor', free_color);
    elseif contains(op, {'COPY', 'MOVE'}), highlight(h, i, 'NodeColor', move_color);
    else, highlight(h, i, 'NodeColor', compute_color); end
end
for i = 1:numedges(subG)
    [s_idx, d_idx] = findedge(subG, i);
    if strcmp(subG.Nodes.Op{s_idx}, 'ALLOC'), highlight(h, 'Edges', i, 'EdgeColor', alloc_color, 'LineWidth', 1.5);
    elseif strcmp(subG.Nodes.Op{d_idx}, 'FREE'), highlight(h, 'Edges', i, 'EdgeColor', free_color, 'LineWidth', 1.5); end
end
h.NodeLabel = strcat('ID:', num2str(subG.Nodes.Id), ', Op:', subG.Nodes.Op);
h.NodeFontSize = 8; h.ArrowSize = 10;
disp('图三生成完毕。');
disp(' ');


%% ========================================================================
% 第五部分：图四 - 计算流时序图 (用于理解宏观执行节律)
% ========================================================================
disp('--- Section 5: Generating Plot 4: Computational Flow Timeline ---');
% --- 图的意义 ---
% 本图是一种"变种甘特图"，用于回答"在整个计算流程中，各个硬件单元的工作状态和负载是怎样的？"
% 它将抽象的依赖关系，映射到了一个直观的、基于硬件单元和执行顺序的坐标系中。
%
% --- 如何理解 ---
% 1. 横轴是"逻辑时间"，代表计算从头到尾的进展；纵轴是并行的硬件单元。
% 2. 每一个点，都是一次真实的操作。点的颜色代表操作类型。
% 3. 请重点观察"点的聚集模式"。例如，您会看到代表"数据加载"(COPY_IN)的色块
%    和代表"核心计算"(CONV)的色块，在图中交替、周期性地出现。
% 4. 这种周期性的模式，就是整个算法的"宏观执行节律"，它直接反映了卷积网络分层计算的本质。
% 5. 在同一个垂直区域（同一时间段），如果多个硬件单元上都有点，则说明它们在"并行"工作。
figure('Name', '图四：计算流时序图 (宏观执行节律)');
topo_order = toposort(G);
plot_x_step = []; plot_y_pipe = {}; plot_group_op = {};
for i = 1:length(topo_order)
    node_id = topo_order(i);
    pipe_type = G.Nodes.Pipe{node_id};
    op_type = G.Nodes.Op{node_id};
    if ischar(pipe_type) && ~isempty(pipe_type)
        plot_x_step(end+1) = i;
        plot_y_pipe{end+1} = pipe_type;
        plot_group_op{end+1} = op_type;
    end
end
gscatter(plot_x_step, categorical(plot_y_pipe), categorical(plot_group_op), [], '.', 15);
title('计算流时序图 (宏观执行节律)');
xlabel('执行步骤 (拓扑序)');
ylabel('硬件执行单元 (Pipe)');
grid on;
legend('Location', 'eastoutside');
disp('图四生成完毕。');
disp(' ');
disp('--- 所有脚本执行完毕 ---');